package mint.modules.generator;

import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import mint.MintLexer;
import mint.modules.symbol.Symbol;
import mint.modules.symbol.SymbolFactory;
import mint.modules.symbol.VariableSymbol;
import mint.modules.type.Type;

import org.antlr.runtime.tree.Tree;

public class ConstructorBodyNode extends Scope implements MintNode {
	private List<MintNode> statements;
	private List<String> errorList;
	private int line;
	
	public ConstructorBodyNode(ConstructorDeclarationNode theParent, Tree ctorBlockTree) {
		super(theParent, theParent.containerClass);
		
		statements = new ArrayList<MintNode>();
		errorList = new ArrayList<String>();
		line = ctorBlockTree.getLine();
		
		for(int i = 0; i < ctorBlockTree.getChildCount(); i++)
		{
			Tree child = ctorBlockTree.getChild(i);
					
			if(child.getType() == MintLexer.LOCALVARIABLEDECLARATION)
			{
				Type type;
				type = Type.getTypeFromTree(child.getChild(0));
				
				for (int j = 1; j < child.getChildCount(); j++)
				{
					VariableDeclarationNode variableNode = new VariableDeclarationNode(this, child.getChild(j), type);
					statements.add(variableNode);
					
					if(!addSymbol(SymbolFactory.createVariableSymbol(variableNode, CounterManager.getInstance().getNewLocal())))
						errorList.add(variableNode.getLine() + ": " + variableNode.getName() + " already exists");					
				}
			}
			else if (child.getType() == MintLexer.EXPRSTMT)
			{
				statements.add(new ExpressionStatementNode(this, child));
			} else if (child.getType() == MintLexer.IF)
			{
				statements.add(new IfThenStmtNode(this, child));
			} else if (child.getType() == MintLexer.WHILE)
			{
				statements.add(new WhileStmtNode(this, child));
			} else if (child.getType() == MintLexer.DOWHILE)
			{
				statements.add(new DoStmtNode(this, child));
			} else if (child.getType() == MintLexer.RETURN)
			{
				statements.add(new ReturnStmtNode(this, child));
			} else if (child.getType() == MintLexer.EXPLICITCONSTRUCTORINV)
			{
				statements.add(new ExplicitConstructorInvocation(this, child));
			}
		}
	}

	@Override
	public void testSemantic() {
		for(MintNode node : statements)
			node.testSemantic();

	}

	@Override
	public List<String> getSemanticErrors() {
		for(MintNode node : statements)
			errorList.addAll(node.getSemanticErrors());
		return errorList;
	}

	@Override
	public void emit(Formatter output) {
		for(MintNode node : statements)
			node.emit(output);
	}

	@Override
	public int getLine() {
		return line;
	}

	@Override
	public void printSymbolTable(Formatter output, int tabSize) {
		for(MintNode node : statements)
		{
			if (node instanceof VariableDeclarationNode)
			{
				VariableDeclarationNode var = (VariableDeclarationNode)node;
				
				VariableSymbol symbol = (VariableSymbol)searchSymbol(var.getName(), getContainerClass(), false);
				
				symbol.print(output, tabSize);
			}
			if (node instanceof Scope)
				((Scope) node).printSymbolTable(output, tabSize);
		}
	}
	
	@Override
	public Symbol searchSymbol(String name, String innerClass, boolean isInheritance) {
		Symbol symbol = super.searchSymbol(name, innerClass, isInheritance);
		
		if(symbol instanceof VariableSymbol)
		{
			if(!((VariableSymbol) symbol).isEnabled())
			{
				return getParent().searchSymbol(name, getContainerClass(), false); 
			} else
				return symbol;
		}
		else
			return super.searchSymbol(name, innerClass, isInheritance);
	}
	
	public ConstructorDeclarationNode getConstructorDeclaration()
	{
		return (ConstructorDeclarationNode)getParent();
	}
}